#include "stdafx.h"
#include "Patcher.h"
#include "lhcutils/Filesystem.h"
#include "lhcutils/Exceptions.h"
#include "OggVorbisException.h"
#include "ogglength.h"
#include "lhcutils/Console.h"
#include "lhcutils/FileStream.h"
#include "FormatNumSeconds.h"
#include <vector>
#include <boost/foreach.hpp>

using namespace lhcutils;
using namespace ogglength;
using namespace std;

namespace itgoggpatch
{

bool Patcher::Patch()
{	
	m_completedWithoutErrors = true;

	// For each path that we were told to patch
	const vector<StringPtr>& startingPaths = m_options.GetStartingPaths();
	BOOST_FOREACH(StringPtr path, startingPaths)
	{
		// Check if the path is a file or a directory
		FileSysEntityType::Value fileType;
		try
		{
			fileType = GetFileSysEntityType(*path, SymlinkBehavior::FollowLinks);
		}
		catch(const FileNotFoundException& ex)
		{
			Console.WriteLine("{0} does not exist. Skipping this file.", *path);
			m_completedWithoutErrors = false;
			continue;
		}
		catch(const IoException& ex)
		{
			m_completedWithoutErrors = false;
			Console.WriteLine("Error with {0}: {1} Skipping this file.", *path, *ex.UnicodeWhat());
			continue;
		}

		if(fileType == FileSysEntityType::Directory)
		{
			LengthPatchDirectory(*path);
		}
		else if(fileType == FileSysEntityType::File)
		{
			LengthPatchFile(*path);
		}
		else
		{
			Console.WriteLine("{0} is a {1}. Only plain files and directories may be patched.", *path, *ToString(fileType));
			m_completedWithoutErrors = false;
		}
	}

	return m_completedWithoutErrors;
}

void Patcher::LengthPatchDirectory(const UnicodeString& directory)
{
	try
	{
		vector<StringPtr> entitiesInDir = GetEntitiesInDirectory(directory);
		BOOST_FOREACH(StringPtr path, entitiesInDir)
		{
			try
			{
				FileSysEntityType::Value fileType = GetFileSysEntityType(*path, SymlinkBehavior::DontFollowLinks);
				if(fileType == FileSysEntityType::Directory)
				{
					LengthPatchDirectory(*path);
				}
				else if(fileType == FileSysEntityType::File)
				{
					LengthPatchFile(*path);
				}
				else if(fileType == FileSysEntityType::Symlink)
				{
					Console.WriteLine("{0} is a symbolic link. Skipping to avoid possible infinite recursion.", *path);
				}
				else
				{
					Console.WriteLine("{0} is a {1}. Skipping.", *path, *ToString(fileType));
				}
			}
			catch(const IoException& ex)
			{
				Console.WriteLine("Error with {0}: {1} Skipping this file.", *path, *ex.UnicodeWhat());
				m_completedWithoutErrors = false;
				continue;
			}
		}
	}
	catch(const IoException& ex)
	{
		Console.WriteLine("Error with {0}: {1} Skipping this directory.", directory, *ex.UnicodeWhat());
		m_completedWithoutErrors = false;
	}
}

void Patcher::LengthPatchFile(const UnicodeString& file)
{
	bool inMiddleOfLine = false;
	FileStream fileStream = FileStream(file, FileOpenMode::OpenExisting, FileAccess::ReadWrite);
	try
	{
		if(m_options.FileMeetsConditions(fileStream))
		{
			double lengthToPatchTo;
			if(m_options.PatchingToRealLength())
			{
				Console.WriteLine("{0}   - getting actual song length...", file);
				lengthToPatchTo = GetRealTime(fileStream);
			}
			else
			{
				lengthToPatchTo = m_options.GetTimeInSecondsToPatchTo();
			}

			Console.Write("{0}   - patching to {1}...", file, *FormatNumSeconds(lengthToPatchTo));
			inMiddleOfLine = true;
			fileStream.Seek(0, SeekOrigin::Begin);
			ChangeSongLength(fileStream, lengthToPatchTo);
			Console.WriteLine("patched.");
			inMiddleOfLine = false;
		}
		else
		{
			// Perhaps we should be more clear to the user about why we are skipping the file.
			Console.WriteLine("{0}   - skipping.", file);
		}
	}
	catch(const OggVorbisException& ex)
	{
		Console.WriteLine("{0}   - ERROR: The file is not an Ogg Vorbis file. Details: {1}", file, *ex.UnicodeWhat());
	}
	catch(const IoException& ex)
	{
		Console.WriteLine("{0}   - ERROR: Error while patching file. Details: {1}", file, *ex.UnicodeWhat());
	}
}

}

/*
 Copyright 2011 Greg Najda

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
